﻿// -----------------------------------------------------------------------
// <copyright company="Christoph van der Fecht - VDsoft">
// Copyright (C) Christoph van der Fecht - VDsoft - All Rights Reserved
// Unauthorized copying of this file, via any medium is strictly prohibited,
// unless it is communicated and authorized by the copyright owner.
// </copyright>
// -----------------------------------------------------------------------

namespace SeriesManager.ViewModel
{
	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.Windows;
	using GalaSoft.MvvmLight;
	using GalaSoft.MvvmLight.Command;
	using GalaSoft.MvvmLight.Messaging;
	using TVDB.Model;
	using TVDB.Web;


	/// <summary>
	/// Search dialog.
	/// </summary>
	public class SearchSeriesViewModel : ViewModelBase
	{
		/// <summary>
		/// Name of the <see cref="Mirrors"/> property.
		/// </summary>
		private const string MirrorsName = "Mirrors";

		/// <summary>
		/// Name of the <see cref="SelectedMirror"/> property.
		/// </summary>
		private const string SelectedMirrorName = "SelectedMirror";

		/// <summary>
		/// Name of the <see cref="BannerAddress"/> property.
		/// </summary>
		private const string BannerAddressName = "BannerAddress";

		/// <summary>
		/// Name of the <see cref="FoundSeries"/> property.
		/// </summary>
		private const string FoundSeriesName = "FoundSeries";

		/// <summary>
		/// Name of the <see cref="SelectedSeries"/> property.
		/// </summary>
		private const string SelectedSeriesName = "SelectedSeries";

		/// <summary>
		/// Name of the <see cref="AvailableLanguages"/> property.
		/// </summary>
		private const string AvailableLanguagesName = "AvailableLanguages";

		/// <summary>
		/// Name of the <see cref="SelectedLanguage"/> property.
		/// </summary>
		private const string SelectedLanguageName = "SelectedLanguage";

		/// <summary>
		/// Name of the <see cref="SearchCriterion"/> property.
		/// </summary>
		private const string SearchCriterionName = "SearchCriterion";

		/// <summary>
		/// Collection of all mirrors.
		/// </summary>
		private ObservableCollection<Mirror> mirrors = new ObservableCollection<Mirror>();

		/// <summary>
		/// The currently selected mirror.
		/// </summary>
		private Mirror selectedMirror = null;

		/// <summary>
		/// The address of the banner to display.
		/// </summary>
		private string bannerAddress = string.Empty;

		/// <summary>
		/// Collection of series that was found with the provided name.
		/// </summary>
		private ObservableCollection<TVDB.Model.Series> foundSeries = new ObservableCollection<Series>();

		/// <summary>
		/// Currently selected series.
		/// </summary>
		private TVDB.Model.Series selectedSeries = null;

		/// <summary>
		/// All langauges that are available on the mirror.
		/// </summary>
		private ObservableCollection<Language> availableLanguages = new ObservableCollection<Language>();

		/// <summary>
		/// Currently selected language.
		/// </summary>
		private Language selectedLanguage = null;

		/// <summary>
		/// The search criterion for the current search.
		/// </summary>
		private string searchCriterion = string.Empty;

		#region private commands

		/// <summary>
		/// Command to get all mirrors.
		/// </summary>
		private RelayCommand getMirrorsCommand = null;

		/// <summary>
		/// Command to search for a series.
		/// </summary>
		private RelayCommand searchSeriesCommand = null;

		/// <summary>
		/// Command to submit the selected series.
		/// </summary>
		private RelayCommand submitSeriesCommand = null;

		#endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="SearchSeriesViewModel"/> class.
		/// </summary>
		public SearchSeriesViewModel()
		{
			if (this.IsInDesignMode)
			{
				Mirror mirror0 = new Mirror()
				{
					Address = "http://thetvdb.com",
					ContainsBannerFile = true,
					ContainsZipFile = true,
					ContainsXmlFile = false
				};

				Mirror mirror1 = new Mirror()
				{
					Address = "http://dummy/mirror",
					ContainsBannerFile = false,
					ContainsXmlFile = true,
					ContainsZipFile = true
				};

				List<Mirror> dummy = new List<Mirror>()
				{
					mirror0,
					mirror1
				};

				List<Language> dummyLanguages = new List<Language>()
				{
					new Language()
					{
						Abbreviation = "en",
						Name = "English"
					},

					new Language()
					{
						Abbreviation = "de",
						Name = "Deutsch"
					}
				};


				this.Mirrors = new ObservableCollection<Mirror>(dummy);
				this.SelectedMirror = mirror0;
				this.BannerAddress = "http://www.thetvdb.com/banners/text/83462.jpg";
				this.AvailableLanguages = new ObservableCollection<Language>(dummyLanguages);
				this.SelectedLanguage = dummyLanguages[0];
			}
			else
			{

			}
		}

		/// <summary>
		/// Event to close the view.
		/// </summary>
		public event EventHandler RequestClose;

		/// <summary>
		/// Gets or sets the collection of all available mirrors.
		/// </summary>
		public ObservableCollection<Mirror> Mirrors
		{
			get
			{
				return this.mirrors;
			}

			set
			{
				if (value == this.mirrors)
				{
					return;
				}

				this.mirrors = value;
				this.RaisePropertyChanged(MirrorsName);
			}
		}

		/// <summary>
		/// Gets or sets the The currently selected mirror.
		/// </summary>
		public Mirror SelectedMirror
		{
			get
			{
				return this.selectedMirror;
			}

			set
			{
				if (value == this.selectedMirror)
				{
					return;
				}

				this.selectedMirror = value;
				this.RaisePropertyChanged(SelectedMirrorName);
				this.GetAllLanguages();
				Messenger.Default.Send<Mirror>(value, ViewModelLocator.SearchSeriesToken);
			}
		}

		/// <summary>
		/// Gets or sets the The address of the banner to display.
		/// </summary>
		public string BannerAddress
		{
			get
			{
				return this.bannerAddress;
			}

			set
			{
				if (value == this.bannerAddress)
				{
					return;
				}

				this.bannerAddress = value;
				this.RaisePropertyChanged(BannerAddressName);
			}
		}

		/// <summary>
		/// Gets or sets the Collection of series that was found with the provided name.
		/// </summary>
		public ObservableCollection<TVDB.Model.Series> FoundSeries
		{
			get
			{
				return this.foundSeries;
			}

			set
			{
				if (value == this.foundSeries)
				{
					return;
				}

				this.foundSeries = value;
				this.RaisePropertyChanged(FoundSeriesName);
			}
		}

		/// <summary>
		/// Gets or sets the Currently selected series.
		/// </summary>
		public TVDB.Model.Series SelectedSeries
		{
			get
			{
				return this.selectedSeries;
			}

			set
			{
				if (value == this.selectedSeries)
				{
					return;
				}

				this.selectedSeries = value;
				this.RaisePropertyChanged(SelectedSeriesName);
				this.BuildBannerImagePath();
			}
		}

		/// <summary>
		/// Gets or sets the All langauges that are available on the mirror.
		/// </summary>
		public ObservableCollection<Language> AvailableLanguages
		{
			get
			{
				return this.availableLanguages;
			}

			set
			{
				if (value == this.availableLanguages)
				{
					return;
				}

				this.availableLanguages = value;
				this.RaisePropertyChanged(AvailableLanguagesName);
			}
		}

		/// <summary>
		/// Gets or sets the Currently selected language.
		/// </summary>
		public Language SelectedLanguage
		{
			get
			{
				return this.selectedLanguage;
			}

			set
			{
				if (value == this.selectedLanguage)
				{
					return;
				}

				this.selectedLanguage = value;
				this.RaisePropertyChanged(SelectedLanguageName);
				this.SearchSeries();
			}
		}

		/// <summary>
		/// Gets or sets the The search criterion for the current search.
		/// </summary>
		public string SearchCriterion
		{
			get
			{
				return this.searchCriterion;
			}

			set
			{
				if (value == this.searchCriterion)
				{
					return;
				}

				this.searchCriterion = value;
				this.RaisePropertyChanged(SearchCriterionName);
			}
		}

		#region public commands

		/// <summary>
		/// Gets the command to request all mirrors.
		/// </summary>
		public RelayCommand GetMirrorsCommand
		{
			get
			{
				if (this.getMirrorsCommand == null)
				{
					this.getMirrorsCommand = new RelayCommand(this.GetMirrors);
				}

				return this.getMirrorsCommand;
			}
		}

		/// <summary>
		/// Gets the command to search for a series.
		/// </summary>
		public RelayCommand SearchSeriesCommand
		{
			get
			{
				if (this.searchSeriesCommand == null)
				{
					this.searchSeriesCommand = new RelayCommand(this.SearchSeries);
				}

				return this.searchSeriesCommand;
			}
		}

		/// <summary>
		/// Gets the command to submit the currently selected series.
		/// </summary>
		public RelayCommand SubmitSeriesCommand
		{
			get
			{
				if (this.submitSeriesCommand == null)
				{
					this.submitSeriesCommand = new RelayCommand(this.SubmitSeries);
				}

				return this.submitSeriesCommand;
			}
		}

		#endregion

		/// <summary>
		/// Search for the series with the name stored in the <see cref="ToSearch"/> property.
		/// </summary>
		public async void SearchSeries()
		{
			if (string.IsNullOrEmpty(this.SearchCriterion))
			{
				return;
			}

			if (this.SelectedMirror == null)
			{
				MessageBox.Show("Please select a mirror.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
				return;
			}

			List<Series> foundSeries = null;


			if (this.SelectedLanguage == null)
			{
				foundSeries = await ViewModelLocator.GetInstance<ITvDb>().GetSeriesByName(this.SearchCriterion, this.SelectedMirror); 
			}
			else
			{
				foundSeries = await ViewModelLocator.GetInstance<ITvDb>().GetSeriesByName(this.SearchCriterion, this.SelectedLanguage.Abbreviation, this.SelectedMirror);
			}

			if (foundSeries.Count == 0)
			{
				Series empty = new Series()
				{
					Name = "No results..."
				};

				this.BannerAddress = string.Empty;
				foundSeries.Add(empty);
			}

			this.FoundSeries = new ObservableCollection<Series>(foundSeries);

			if (foundSeries.Count == 1)
			{
				this.SelectedSeries = foundSeries[0];
			}
		}

		/// <summary>
		/// Gets all available mirrors.
		/// </summary>
		private async void GetMirrors()
		{
			List<Mirror> mirrors = await ViewModelLocator.GetInstance<ITvDb>().GetMirrors();

			this.Mirrors = new ObservableCollection<Mirror>(mirrors);
		}

		/// <summary>
		/// Builds the banner path of the current selected series.
		/// </summary>
		private void BuildBannerImagePath()
		{
			if (this.SelectedSeries == null)
			{
				return;
			}

			if (!string.IsNullOrEmpty(this.SelectedSeries.Banner))
			{
				this.BannerAddress = string.Format("{0}/banners/{1}",this.SelectedMirror.Address , this.SelectedSeries.Banner);
			}
			else if (!string.IsNullOrEmpty(this.SelectedSeries.Poster))
			{
				this.BannerAddress = string.Format("{0}/banners/{1}", this.SelectedMirror.Address, this.SelectedSeries.Poster);
			}
			else if (!string.IsNullOrEmpty(this.SelectedSeries.FanArt))
			{
				this.BannerAddress = string.Format("{0}/banners/{1}", this.SelectedMirror.Address, this.SelectedSeries.FanArt);
			}
			else
			{
				this.BannerAddress = string.Empty;
			}
		}

		/// <summary>
		/// Submits the current selected series.
		/// </summary>
		private async void SubmitSeries()
		{
			if (this.SelectedSeries == null)
			{
				return;
			}

			SeriesDetails submitted = null;

			if (this.SelectedLanguage == null)
			{
				submitted = await ViewModelLocator.GetInstance<ITvDb>().GetFullSeriesById(this.SelectedSeries.Id, this.SelectedMirror);
			}
			else
			{
				submitted = await ViewModelLocator.GetInstance<ITvDb>().GetFullSeriesById(this.SelectedSeries.Id, this.SelectedLanguage.Abbreviation, this.SelectedMirror);
			}

			Messenger.Default.Send<SeriesDetails>(submitted, ViewModelLocator.SearchSeriesToken);

			if (this.RequestClose != null)
			{
				this.RequestClose(this, EventArgs.Empty);
			}
		}

		/// <summary>
		/// Requests all availabel Langauges form the selected mirror.
		/// </summary>
		private async void GetAllLanguages()
		{
			if (this.SelectedMirror == null)
			{
				return;
			}

			List<Language> received = await ViewModelLocator.GetInstance<ITvDb>().GetLanguages(this.SelectedMirror);

			this.AvailableLanguages = new ObservableCollection<Language>(received);
		}
	}
}
